﻿//-----------------------------------------------------------------------
// <copyright file="Program.cs" company="DylanBox">
// Copyright (c) DylanBox Corporation. All rights reserved.
// </copyright>
// <summary></summary>
// <reference>
//      <<3>>
//    This is a practical demo of DelegateAndEvent
//     
//    You have a class with a special number. You have another (or may be a lot of other) class which is using it. 
//    The requirement now is that, whenever the special number is changed, all the other guys should be notified about what this number was and what it has become!
//
//   Ref: http://www.dotnetscraps.com/dotnetscraps/post/Explaining-Delegates-in-C-Part-3-(Events-again).aspx
// </reference>
// <author>Dylan</author>
//-----------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace AnyoneGetKnowChange
{
    class Program
    {
        //There are 3 rules which are MANDATORY when you are planning to create events
        //Rule 1> The delegate must be defined with two arguments
        //Rule 2> These arguments always represent TWO objects… 
        //          The Publisher (object that raised the event)
        //          Event Information object
        //Rule 3> The 2nd object HAS to be derived from EventArgs

        //Step 1> Create a class that inherits from EventArgs (To comply with Rule 3)
        class NotifyChangeEventArgs : EventArgs
        {
            //constructor to initialize the SpecialNumberOld and SpecialNumberNew property
            public NotifyChangeEventArgs(int SpecialNumberOld, int SpecialNumberNew)
            {
                this.SpecialNumberNew = SpecialNumberNew;
                this.SpecialNumberOld = SpecialNumberOld;
            }
            public int SpecialNumberNew { get; set; }
            public int SpecialNumberOld { get; set; }
        };

        class SpecialNumberClass // Publisher
        {
            //Publisher declares a special delegate and event (Rule 1 & 2)
            public delegate void SpecialNumberHandler(object source, NotifyChangeEventArgs e);
            public event SpecialNumberHandler OnSpecialNumberUpdate;

            //Constructor to set the value of the _specialNumber directly.
            //Notice that we are not setting the SpecialNumber property!
            public SpecialNumberClass(int number)
            {
                _specialNumber = number;
            }

            //This property will fire an event called OnSpecialNumberUpdate whenever called
            //The effect is that is the special number is changed from outside, all the guys
            //would be notified. It is upto them to listen to it or not listen to it.
            private int _specialNumber;
            public int SpecialNumber
            {
                get { return _specialNumber; }
                //Put a breakpoint here on set and step into (F11)
                set
                {
                    if (OnSpecialNumberUpdate != null)
                    {
                        //This is the guy who would fire that notify event called OnSpecialNumberUpdate
                        //Basically, before you fire that event, you can set up that value for EventArgs
                        //In my case, I have set the value of e's old value and new value...
                        //to the _specialNumber and value (which would be the new value)
                        //Notice that we are just firing the events with appropriate EventArgs...
                        //We haven't thrown any output as such yet!!!!
                        NotifyChangeEventArgs e = new NotifyChangeEventArgs(_specialNumber, value);
                        Console.WriteLine("Raising Events to all the subscribers...\n");
                        OnSpecialNumberUpdate(this, e);
                    }
                }
            }
        };

        class SpecialNumberUpdateListener // Subscriber
        {
            private string _listenerName;

            //Here we are just creating a new Object called objSN for my SpecialNumberClass
            SpecialNumberClass objSN;

            //In this method, I would go ahead and bind my event
            public SpecialNumberUpdateListener(string listenerName, SpecialNumberClass spClass)
            {
                _listenerName = listenerName;

                Console.WriteLine("SpecialNumber listener {0} > Subscribing to the event...\n", listenerName);
                this.objSN = spClass;

                //Wiring the event so that the event is fired
                spClass.OnSpecialNumberUpdate += new SpecialNumberClass.SpecialNumberHandler(OnSpecialNumberUpdate);                
            }

            //This is the event that would be invoked whenever you change the value
            //Try putting a break point here and see how it gets hit when the number changes
            //Also notice how we use the Event args to grab the details and finally print it out
            void OnSpecialNumberUpdate(object source, NotifyChangeEventArgs e)
            {
                Console.WriteLine("{0} know it, the number has changed from {1} to {2} ", _listenerName, e.SpecialNumberOld, e.SpecialNumberNew);
            }
        }

        class EventDemo
        {
            public static void Main()
            {
                //Creating a new Special Number (Publisher) class with initial value of 20
                SpecialNumberClass snc = new SpecialNumberClass(30);
                
                //Creating a Subscriber/listener class
                SpecialNumberUpdateListener s = new SpecialNumberUpdateListener("Dylan", snc);
                SpecialNumberUpdateListener t = new SpecialNumberUpdateListener("Sally", snc);
                
                //Changing the value so that the event is triggered.
                //Put a breakpoint and step into the code (F11)
                snc.SpecialNumber = 40;
                Console.ReadLine();
            }
        }

    }
}
